package com.chunfen.dubbo.protocol.dubbo;

import com.chunfen.dubbo.framework.Invocation;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NettyClient<T> {
    public NettyClientHandler client = null;

    private static ExecutorService executorService = Executors.newCachedThreadPool();

    public  void start(String hostName, Integer port)  throws Exception {
        client = new NettyClientHandler();

        Bootstrap bootstrap = new Bootstrap();
        EventLoopGroup group = new NioEventLoopGroup();

        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer(){
                    @Override
                    protected void initChannel(Channel channel) throws Exception {

                        ChannelPipeline pipeline = channel.pipeline();
                        pipeline.addLast("decoder",
                                new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));

                        pipeline.addLast("encoder", new ObjectEncoder());
                        pipeline.addLast("handler", client);

                    }
                });

        try {

            bootstrap.connect(hostName, port).sync();

        } catch (Exception e){
            e.printStackTrace();
        } finally {
            group.shutdownGracefully(); // 释放线程池资源
        }
    }

    public Map<String, ? extends Serializable> send(String hostName, Integer port, Invocation invocation) throws Exception{
        if(client == null){
            start(hostName, port);
        }

        client.setInvocation(invocation);

        try {
            return (Map<String, ? extends Serializable>) executorService.submit(client).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
